using Microsoft.Extensions.Logging;
using SeataNet.Core.Common;
using SeataNet.Core.RPC;

namespace SeataNet.Core.Cluster
{
    /// <summary>
    /// 负载均衡策略
    /// </summary>
    public enum LoadBalanceStrategy
    {
        /// <summary>
        /// 轮询
        /// </summary>
        RoundRobin,

        /// <summary>
        /// 随机
        /// </summary>
        Random,

        /// <summary>
        /// 最少连接
        /// </summary>
        LeastConnections,

        /// <summary>
        /// 一致性哈希
        /// </summary>
        ConsistentHash,

        /// <summary>
        /// 加权轮询
        /// </summary>
        WeightedRoundRobin,

        /// <summary>
        /// 加权随机
        /// </summary>
        WeightedRandom
    }

    /// <summary>
    /// 负载均衡器接口
    /// </summary>
    public interface ILoadBalancer
    {
        /// <summary>
        /// 选择节点
        /// </summary>
        /// <param name="nodes">可用节点列表</param>
        /// <param name="key">选择键（用于一致性哈希）</param>
        /// <returns>选择的节点</returns>
        ClusterNode? SelectNode(List<ClusterNode> nodes, string? key = null);

        /// <summary>
        /// 更新节点权重
        /// </summary>
        /// <param name="nodeId">节点ID</param>
        /// <param name="weight">权重</param>
        void UpdateNodeWeight(string nodeId, int weight);

        /// <summary>
        /// 更新节点连接数
        /// </summary>
        /// <param name="nodeId">节点ID</param>
        /// <param name="increment">是否增加</param>
        void UpdateNodeConnections(string nodeId, bool increment = true);

        /// <summary>
        /// 获取节点统计信息
        /// </summary>
        /// <param name="nodeId">节点ID</param>
        /// <returns>节点统计信息</returns>
        NodeStatistics? GetNodeStatistics(string nodeId);

        /// <summary>
        /// 重置统计信息
        /// </summary>
        void ResetStatistics();
    }

    /// <summary>
    /// 默认负载均衡器实现
    /// </summary>
    public class DefaultLoadBalancer : ILoadBalancer
    {
        private readonly ILogger<DefaultLoadBalancer> _logger;
        private readonly IClusterManager _clusterManager;
        private readonly LoadBalanceConfiguration _configuration;

        private readonly object _roundRobinLock = new object();
        private int _roundRobinIndex = 0;

        private readonly Random _random = new Random();
        private readonly Dictionary<string, NodeStatistics> _nodeStatistics;

        public DefaultLoadBalancer(
            ILogger<DefaultLoadBalancer> logger,
            IClusterManager clusterManager,
            LoadBalanceConfiguration configuration)
        {
            _logger = logger;
            _clusterManager = clusterManager;
            _configuration = configuration;
            _nodeStatistics = new Dictionary<string, NodeStatistics>();
        }

        public ClusterNode? SelectNode(List<ClusterNode> nodes, string? key = null)
        {
            if (nodes == null || !nodes.Any())
            {
                _logger.LogWarning("No available nodes for load balancing");
                return null;
            }

            try
            {
                var availableNodes = nodes.Where(n => n.Status == NodeStatus.Available && n.IsAlive).ToList();
                if (!availableNodes.Any())
                {
                    _logger.LogWarning("No healthy nodes available for load balancing");
                    return null;
                }

                switch (_configuration.Strategy)
                {
                    case LoadBalanceStrategy.RoundRobin:
                        return SelectRoundRobinNode(availableNodes);

                    case LoadBalanceStrategy.Random:
                        return SelectRandomNode(availableNodes);

                    case LoadBalanceStrategy.LeastConnections:
                        return SelectLeastConnectionsNode(availableNodes);

                    case LoadBalanceStrategy.ConsistentHash:
                        return SelectConsistentHashNode(availableNodes, key);

                    case LoadBalanceStrategy.WeightedRoundRobin:
                        return SelectWeightedRoundRobinNode(availableNodes);

                    case LoadBalanceStrategy.WeightedRandom:
                        return SelectWeightedRandomNode(availableNodes);

                    default:
                        _logger.LogWarning("Unknown load balance strategy: {Strategy}, using RoundRobin", _configuration.Strategy);
                        return SelectRoundRobinNode(availableNodes);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error selecting node with load balancer");
                return null;
            }
        }

        public void UpdateNodeWeight(string nodeId, int weight)
        {
            if (!_nodeStatistics.ContainsKey(nodeId))
            {
                _nodeStatistics[nodeId] = new NodeStatistics { NodeId = nodeId };
            }

            _nodeStatistics[nodeId].Weight = weight;
            _logger.LogDebug("Updated node weight, Node ID: {NodeId}, Weight: {Weight}", nodeId, weight);
        }

        public void UpdateNodeConnections(string nodeId, bool increment = true)
        {
            if (!_nodeStatistics.ContainsKey(nodeId))
            {
                _nodeStatistics[nodeId] = new NodeStatistics { NodeId = nodeId };
            }

            if (increment)
            {
                _nodeStatistics[nodeId].ActiveConnections++;
            }
            else
            {
                _nodeStatistics[nodeId].ActiveConnections = Math.Max(0, _nodeStatistics[nodeId].ActiveConnections - 1);
            }

            _logger.LogDebug("Updated node connections, Node ID: {NodeId}, Connections: {Connections}", 
                nodeId, _nodeStatistics[nodeId].ActiveConnections);
        }

        public NodeStatistics? GetNodeStatistics(string nodeId)
        {
            return _nodeStatistics.TryGetValue(nodeId, out var stats) ? stats : null;
        }

        public void ResetStatistics()
        {
            foreach (var stats in _nodeStatistics.Values)
            {
                stats.ActiveConnections = 0;
                stats.TotalRequests = 0;
                stats.FailedRequests = 0;
                stats.AverageResponseTime = 0;
                stats.LastRequestTime = null;
            }

            _logger.LogInformation("Reset all node statistics");
        }

        /// <summary>
        /// 轮询选择节点
        /// </summary>
        private ClusterNode? SelectRoundRobinNode(List<ClusterNode> nodes)
        {
            lock (_roundRobinLock)
            {
                if (_roundRobinIndex >= nodes.Count)
                {
                    _roundRobinIndex = 0;
                }

                var selectedNode = nodes[_roundRobinIndex];
                _roundRobinIndex++;

                _logger.LogDebug("Selected node using RoundRobin strategy, Node ID: {NodeId}", selectedNode.NodeId);
                UpdateNodeStatistics(selectedNode.NodeId);
                return selectedNode;
            }
        }

        /// <summary>
        /// 随机选择节点
        /// </summary>
        private ClusterNode? SelectRandomNode(List<ClusterNode> nodes)
        {
            var index = _random.Next(nodes.Count);
            var selectedNode = nodes[index];

            _logger.LogDebug("Selected node using Random strategy, Node ID: {NodeId}", selectedNode.NodeId);
            UpdateNodeStatistics(selectedNode.NodeId);
            return selectedNode;
        }

        /// <summary>
        /// 选择最少连接的节点
        /// </summary>
        private ClusterNode? SelectLeastConnectionsNode(List<ClusterNode> nodes)
        {
            var selectedNode = nodes
                .OrderBy(n => GetNodeConnections(n.NodeId))
                .First();

            _logger.LogDebug("Selected node using LeastConnections strategy, Node ID: {NodeId}, Connections: {Connections}", 
                selectedNode.NodeId, GetNodeConnections(selectedNode.NodeId));
            UpdateNodeStatistics(selectedNode.NodeId);
            return selectedNode;
        }

        /// <summary>
        /// 一致性哈希选择节点
        /// </summary>
        private ClusterNode? SelectConsistentHashNode(List<ClusterNode> nodes, string? key)
        {
            if (string.IsNullOrEmpty(key))
            {
                _logger.LogWarning("Key is null or empty for ConsistentHash strategy, falling back to RoundRobin");
                return SelectRoundRobinNode(nodes);
            }

            // 简单的一致性哈希实现
            var hash = key.GetHashCode();
            var index = Math.Abs(hash) % nodes.Count;
            var selectedNode = nodes[index];

            _logger.LogDebug("Selected node using ConsistentHash strategy, Key: {Key}, Node ID: {NodeId}", key, selectedNode.NodeId);
            UpdateNodeStatistics(selectedNode.NodeId);
            return selectedNode;
        }

        /// <summary>
        /// 加权轮询选择节点
        /// </summary>
        private ClusterNode? SelectWeightedRoundRobinNode(List<ClusterNode> nodes)
        {
            lock (_roundRobinLock)
            {
                // 计算总权重
                var totalWeight = nodes.Sum(n => GetNodeWeight(n.NodeId));
                if (totalWeight <= 0)
                {
                    // 如果没有设置权重，使用普通轮询
                    return SelectRoundRobinNode(nodes);
                }

                // 根据权重选择节点
                var currentWeight = 0;
                foreach (var node in nodes)
                {
                    currentWeight += GetNodeWeight(node.NodeId);
                    if (_roundRobinIndex < currentWeight)
                    {
                        _roundRobinIndex = (_roundRobinIndex + 1) % totalWeight;
                        _logger.LogDebug("Selected node using WeightedRoundRobin strategy, Node ID: {NodeId}, Weight: {Weight}", 
                            node.NodeId, GetNodeWeight(node.NodeId));
                        UpdateNodeStatistics(node.NodeId);
                        return node;
                    }
                }

                // 如果没有选中，选择第一个节点
                _roundRobinIndex = (_roundRobinIndex + 1) % totalWeight;
                var selectedNode = nodes.First();
                _logger.LogDebug("Selected node using WeightedRoundRobin strategy (fallback), Node ID: {NodeId}", selectedNode.NodeId);
                UpdateNodeStatistics(selectedNode.NodeId);
                return selectedNode;
            }
        }

        /// <summary>
        /// 加权随机选择节点
        /// </summary>
        private ClusterNode? SelectWeightedRandomNode(List<ClusterNode> nodes)
        {
            // 计算总权重
            var totalWeight = nodes.Sum(n => GetNodeWeight(n.NodeId));
            if (totalWeight <= 0)
            {
                // 如果没有设置权重，使用普通随机
                return SelectRandomNode(nodes);
            }

            // 生成随机数
            var randomWeight = _random.Next(totalWeight);

            // 根据权重选择节点
            var currentWeight = 0;
            foreach (var node in nodes)
            {
                currentWeight += GetNodeWeight(node.NodeId);
                if (randomWeight < currentWeight)
                {
                    _logger.LogDebug("Selected node using WeightedRandom strategy, Node ID: {NodeId}, Weight: {Weight}", 
                        node.NodeId, GetNodeWeight(node.NodeId));
                    UpdateNodeStatistics(node.NodeId);
                    return node;
                }
            }

            // 如果没有选中，选择最后一个节点
            var selectedNode = nodes.Last();
            _logger.LogDebug("Selected node using WeightedRandom strategy (fallback), Node ID: {NodeId}", selectedNode.NodeId);
            UpdateNodeStatistics(selectedNode.NodeId);
            return selectedNode;
        }

        /// <summary>
        /// 获取节点连接数
        /// </summary>
        private int GetNodeConnections(string nodeId)
        {
            return _nodeStatistics.TryGetValue(nodeId, out var stats) ? stats.ActiveConnections : 0;
        }

        /// <summary>
        /// 获取节点权重
        /// </summary>
        private int GetNodeWeight(string nodeId)
        {
            if (_nodeStatistics.TryGetValue(nodeId, out var stats))
            {
                return stats.Weight > 0 ? stats.Weight : _configuration.DefaultWeight;
            }

            // 从集群管理器获取节点信息
            var node = _clusterManager.GetClusterNodes().FirstOrDefault(n => n.NodeId == nodeId);
            if (node != null)
            {
                // 使用节点优先级作为权重
                return node.Priority > 0 ? node.Priority : _configuration.DefaultWeight;
            }

            return _configuration.DefaultWeight;
        }

        /// <summary>
        /// 更新节点统计信息
        /// </summary>
        private void UpdateNodeStatistics(string nodeId)
        {
            if (!_nodeStatistics.ContainsKey(nodeId))
            {
                _nodeStatistics[nodeId] = new NodeStatistics { NodeId = nodeId };
            }

            var stats = _nodeStatistics[nodeId];
            stats.TotalRequests++;
            stats.LastRequestTime = DateTime.UtcNow;
        }
    }

    /// <summary>
    /// 节点统计信息
    /// </summary>
    public class NodeStatistics
    {
        /// <summary>
        /// 节点ID
        /// </summary>
        public string NodeId { get; set; } = string.Empty;

        /// <summary>
        /// 权重
        /// </summary>
        public int Weight { get; set; } = 1;

        /// <summary>
        /// 活跃连接数
        /// </summary>
        public int ActiveConnections { get; set; }

        /// <summary>
        /// 总请求数
        /// </summary>
        public long TotalRequests { get; set; }

        /// <summary>
        /// 失败请求数
        /// </summary>
        public long FailedRequests { get; set; }

        /// <summary>
        /// 平均响应时间（毫秒）
        /// </summary>
        public double AverageResponseTime { get; set; }

        /// <summary>
        /// 最后请求时间
        /// </summary>
        public DateTime? LastRequestTime { get; set; }
    }

    /// <summary>
    /// 负载均衡配置
    /// </summary>
    public class LoadBalanceConfiguration
    {
        /// <summary>
        /// 负载均衡策略
        /// </summary>
        public LoadBalanceStrategy Strategy { get; set; } = LoadBalanceStrategy.RoundRobin;

        /// <summary>
        /// 默认权重
        /// </summary>
        public int DefaultWeight { get; set; } = 1;

        /// <summary>
        /// 是否启用健康检查
        /// </summary>
        public bool EnableHealthCheck { get; set; } = true;

        /// <summary>
        /// 健康检查间隔（秒）
        /// </summary>
        public int HealthCheckIntervalSeconds { get; set; } = 30;

        /// <summary>
        /// 失败阈值
        /// </summary>
        public int FailureThreshold { get; set; } = 3;

        /// <summary>
        /// 恢复阈值
        /// </summary>
        public int RecoveryThreshold { get; set; } = 2;
    }
}